﻿
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client.Receiving;
using MQTTnet.Protocol;
using MQTTnet.Server;
using MQTTServer.Models;
using MQTTServer.Models.entity;
using MQTTServer.Models.Response;
using Newtonsoft.Json;
using RestSharp;
using System.Text;
using System.Text.RegularExpressions;

namespace MQTTServer.Services
{
    public class MQTTService
    {
        private readonly ConfigHelper configuration = new ConfigHelper();
        private IMqttServer mqttServer;
        private List<MqttApplicationMessage> messages = new List<MqttApplicationMessage>();
        private readonly RestClient client;
        public MQTTService()
        {
            client = new RestClient(configuration.GetSettings("ApiUrl"));
        }
        public class UserInstance
        {
            public string ClientId { get; set; }
            public string UserName { get; set; }
            public string Password { get; set; }
        }
        public async Task StartMqttServer()
        {
            try
            {
                if (mqttServer == null)
                {
                    var optionsBuilder = new MqttServerOptionsBuilder()
                    .WithDefaultEndpoint()
                    .WithDefaultEndpointPort(Convert.ToInt32(configuration.GetSettings("MQTTConfig:Port")))
                    //连接拦截器
                    .WithConnectionValidator(
                        c =>
                        {
                            var flag = c.Username == configuration.GetSettings("MQTTConfig:UserName") && c.Password == configuration.GetSettings("MQTTConfig:Password");
                            if (!flag)
                            {
                                c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
                                return;
                            }
                            //设置代码为 Success
                            c.ReasonCode = MqttConnectReasonCode.Success;
                            //instances.Add(new UserInstance()  //缓存到内存的List集合当中
                            //{
                            //    ClientId = c.ClientId,
                            //    UserName = c.Username,
                            //    Password = c.Password
                            //});
                        })
                    //订阅拦截器
                    .WithSubscriptionInterceptor(
                        c =>
                        {
                            if (c == null) return;
                            c.AcceptSubscription = true;
                        })
                    //应用程序消息拦截器
                    .WithApplicationMessageInterceptor(
                        c =>
                        {
                            if (c == null) return;
                            c.AcceptPublish = true;
                        })
                   //clean sesison是否生效
                   .WithPersistentSessions();

                    mqttServer = new MqttFactory().CreateMqttServer();

                    //客户端断开连接拦截器
                    //mqttServer.UseClientDisconnectedHandler(c =>
                    //{
                    //    //var user = instances.FirstOrDefault(t => t.ClientId == c.ClientId);
                    //    //if (user != null)
                    //    //{
                    //    //    instances.Remove(user);
                    //    //}
                    //});

                    //服务开始
                    mqttServer.StartedHandler = new MqttServerStartedHandlerDelegate(OnMqttServerStarted);
                    //服务停止
                    mqttServer.StoppedHandler = new MqttServerStoppedHandlerDelegate(OnMqttServerStopped);
                    //客户端连接
                    mqttServer.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(OnMqttServerClientConnected);
                    //客户端断开连接（此事件会覆盖拦截器）
                    mqttServer.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(OnMqttServerClientDisconnected);
                    //客户端订阅
                    mqttServer.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(OnMqttServerClientSubscribedTopic);
                    //客户端取消订阅
                    mqttServer.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(OnMqttServerClientUnsubscribedTopic);
                    //服务端收到消息
                    mqttServer.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(OnMqttServerApplicationMessageReceived);

                    await mqttServer.StartAsync(optionsBuilder.Build());

                    //主动发送消息到客户端
                    //await mqttServer.PublishAsync(new
                    //     MqttApplicationMessage
                    //{
                    //    Topic = "testtopic",
                    //    Payload = Encoding.UTF8.GetBytes("dsdsd")
                    //});
                    //mqttServer.GetClientStatusAsync();
                    //mqttServer.GetRetainedApplicationMessagesAsync();
                    //mqttServer.GetSessionStatusAsync();

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"MQTT Server start fail.>{ex.Message}");
            }
        }
        private void OnMqttServerStarted(EventArgs e)
        {
            if (mqttServer.IsStarted)
            {
                Console.WriteLine("MQTT服务启动完成！");
            }
        }
        private void OnMqttServerStopped(EventArgs e)
        {
            if (!mqttServer.IsStarted)
            {
                Console.WriteLine("MQTT服务停止完成！");
            }
        }
        private void OnMqttServerClientConnected(MqttServerClientConnectedEventArgs e)
        {
            Console.WriteLine($"客户端[{e.ClientId}]已连接");
        }
        private void OnMqttServerClientDisconnected(MqttServerClientDisconnectedEventArgs e)
        {
            Console.WriteLine($"客户端[{e.ClientId}]已断开连接！");
        }
        private void OnMqttServerClientSubscribedTopic(MqttServerClientSubscribedTopicEventArgs e)
        {
            Console.WriteLine($"客户端[{e.ClientId}]已成功订阅主题[{e.TopicFilter}]！");
        }
        private void OnMqttServerClientUnsubscribedTopic(MqttServerClientUnsubscribedTopicEventArgs e)
        {
            Console.WriteLine($"客户端[{e.ClientId}]已成功取消订阅主题[{e.TopicFilter}]！");
        }
        private void OnMqttServerApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
        {
            //messages.Add(e.ApplicationMessage);
            //Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"));
            //Console.WriteLine($"客户端[{e.ClientId}]>> Topic[{e.ApplicationMessage.Topic}] Payload[{Encoding.UTF8.GetString(e.ApplicationMessage.Payload ?? new byte[] { })}] Qos[{e.ApplicationMessage.QualityOfServiceLevel}] Retain[{e.ApplicationMessage.Retain}]");


            //string bbb = Encoding.UTF8.GetString(e.ApplicationMessage.Payload ?? new byte[] { });
            //if (e.ApplicationMessage.Topic.Contains("RecPush"))
            //{
            //    string aaa = Encoding.UTF8.GetString(e.ApplicationMessage.Payload ?? new byte[] { });
            //}

            Response(e.ApplicationMessage);

        }


        #region 业务
        private void Response(MqttApplicationMessage applicationMessage)
        {

            string msg = Encoding.UTF8.GetString(applicationMessage.Payload ?? new byte[] { });
            string topIc = Uri.UnescapeDataString(applicationMessage.Topic);
            switch (topIc)
            {
                case Constants.HQ_Basic:
                    Basic_HQ(msg);
                    break;
                case Constants.QY_Basic:
                    Basic_QY(msg);
                    break;
                default:
                    #region 海清
                    //判断是否是人脸识别订阅
                    if (Regex.IsMatch(topIc, @"^mqtt/face/(\d+)/Rec$"))
                    {
                        RecPush(msg);
                    }
                    else if (Regex.IsMatch(topIc, @"^mqtt/face/(\d+)$"))
                    {
                        Console.WriteLine($"收到客户端消息:{msg}");
                    }
                    //消息发送结果订阅
                    else if (Regex.IsMatch(topIc, @"^mqtt/face/(\d+)/Ack$"))
                    {
                        Console.WriteLine($"收到设备消息:{msg}");
                        Ack(msg);
                    }
                    #endregion

                    #region 芊熠


                    //else if (topIc == "/hiot/record_message")
                    //{
                    //    Console.WriteLine($"收到人脸识别消息:{msg}");
                    //}

                    //else if (topIc == "/hio/device_cmd_reply")
                    //{
                    //    Console.WriteLine($"收到下发重启命令回调:{msg}");
                    //}

                    //else if (topIc == "/hio/sync_people_reply")
                    //{
                    //    Console.WriteLine($"收到下发重启命令回调:{msg}");
                    //}
                    #endregion

                    break;
            }
        }

        #region 海清

        /// <summary>
        /// 下发结果推送
        /// </summary>
        /// <param name="messages"></param>
        public void Ack(string message)
        {
            AckModel? ackModel = JsonConvert.DeserializeObject<AckModel>(message);
            if (ackModel == null) return;
            AckEntity entity = new AckEntity()
            {
                messageId = ackModel.messageId,
                code = ackModel.code,
                result = ackModel.info.result,
                result_time = DateTime.Now,

            };
            RestRequest request = new RestRequest("/api/CommandAck", Method.Post);
            request.AddBody(entity, ContentType.Json);
            Execute(request);
        }


        /// <summary>
        /// 认证识别结果推送
        /// </summary>
        /// <param name="message"></param>
        private void RecPush(string message)
        {
            RecPushModel? recPushModel = JsonConvert.DeserializeObject<RecPushModel>(message);
            if (recPushModel == null) return;
            var info = recPushModel.info;
            RecPushEntity entity = new RecPushEntity()
            {
                DeviceCode = info.facesluiceId,
                IdCard = info.idCard,
                Similarity = info.similarity1 / 100,
                CameraPhoto = info.pic,
                VerifyTime = info.time,
                CreateTime = DateTime.Now,
            };
            RestRequest request = new RestRequest("/api/RecPush", Method.Post);
            request.AddBody(entity, ContentType.Json);
            Execute(request);
        }

        /// <summary>
        /// 设备上线下线通知
        /// </summary>
        /// <param name="message"></param>
        private void Basic_HQ(string message)
        {
            HQBasicModel? basicModel = JsonConvert.DeserializeObject<HQBasicModel>(message);
            if (basicModel == null) return;
            DeviceEntity deviceModel = new DeviceEntity()
            {
                Code = basicModel.info.facesluiceId,
                Name = basicModel.info.FacesName,
                IsOnline = basicModel.Operator == "Online" ? true : false,
                IpAddress = basicModel.info.Ip,
                LastSyncTime = basicModel.info.Time
            };

            RestRequest request = new RestRequest("/api/updateDeviceAsync", Method.Post);
            request.AddBody(deviceModel, ContentType.Json);
            Execute(request);
        }

        #endregion

        #region 芊熠

        /// <summary>
        /// 设备上线下线通知
        /// </summary>
        /// <param name="message"></param>
        private void Basic_QY(string message)
        {
            QYBasicModel? basicModel = JsonConvert.DeserializeObject<QYBasicModel>(message);
            if (basicModel == null) return;
            DeviceEntity deviceModel = new DeviceEntity()
            {
                Code = basicModel.mac_address,
                Name = basicModel.device_name,
                IsOnline = basicModel.online == 1 ? true : false,
                IpAddress = basicModel.device_ip
            };

            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));//当地时区
            deviceModel.LastSyncTime = startTime.AddSeconds(basicModel.time);

            RestRequest request = new RestRequest("/api/updateDeviceAsync", Method.Post);
            request.AddBody(deviceModel, ContentType.Json);
            Execute(request);
        }
        #endregion

        #endregion

        public ServiceResult Execute(RestRequest request)
        {
            var response = client.Execute<ServiceResult>(request);

            if (response.ErrorException != null)
            {
                return new ServiceResult { msg = "MQTT内部通讯失败" };
            }
            return response.Data;
        }
    }
}
